package mi.payment.utils.transaction;

import android.text.TextUtils;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import lainey.ui.utils.LogUtil;
import mi.payment.Constant;
import mi.payment.constants.Configs;
import mi.payment.settings.NetworkDataOperations;
import mi.payment.settings.NetworkParamSettings;
import mi.payment.utils.iso8583.Utils;
import mi.payment.utils.secure.TerminalSecure;

public class POSPAccess {

    private static final int DEFAULT_TIMEOUT = 30 * 1000; // 默认超时时间30s
    private String serverIP; // 服务IP
    private int serverPort; // 服务器端口
    private int connectTimeout = 20; // 连接超时时间,单位秒
    private int socketTimeout = 10; // 读超时时间,单位秒
    private int receiveDataLen = 21; // 默认返回报文长度校验

    private Socket socket;                  // Socket对象
    private InputStream inputStream;        // Socket输入流
    private OutputStream outputStream;      // Socket输出流

    public POSPAccess() {
        initIPAndPort();
        checkIpAndPort();
        initTimeout();
    }

    public POSPAccess(String address, int port) {
        serverIP = address;
        serverPort = port;
        checkIpAndPort();
        initTimeout();
    }

    public void setServerIP(String ip) {
        serverIP = ip;
    }

    public void setServerPort(int port) {
        serverPort = port;
    }

    public void setReceiveDataLen(int len) {
        receiveDataLen = len;
    }

    /**
     * 初始化IP和端口
     */
    private void initIPAndPort() {
        NetworkParamSettings networkParamSettings = NetworkDataOperations.getInstance().getNetworkParamSettings();
        if (networkParamSettings.getNetworkDefaultConfiguration() == 1) {
            // 配置1
            serverIP = networkParamSettings.getHostIpAddress();
            serverPort = Integer.parseInt(networkParamSettings.getHostPort());
        } else {
            // 配置2,使用备份的IP和端口
            serverIP = networkParamSettings.getSpareHostIpAddress();
            serverPort = Integer.parseInt(networkParamSettings.getSpareHostPort());
        }
        String mSpareHostIpAddress = networkParamSettings.getSpareHostIpAddress();
        String SpareHostPort = networkParamSettings.getSpareHostPort();

        boolean autoSwitchIP = Configs.getInstance().AUTO_SWITCH_IP();
        boolean useBackupIP = Configs.getInstance().USE_BACKUP_IP();
        if (autoSwitchIP && useBackupIP && !TextUtils.isEmpty(mSpareHostIpAddress) && !TextUtils.isEmpty(SpareHostPort)) {
            // 配置2,使用备份的IP和端口
            serverIP = networkParamSettings.getSpareHostIpAddress();
            serverPort = Integer.parseInt(networkParamSettings.getSpareHostPort());
        }
    }

    /**
     * 检查IP和端口是否合法
     */
    private void checkIpAndPort() {
        if (!validIP(serverIP)) {
            throw new RuntimeException("illegal server ip!");
        }
        if (serverPort <= 0) {
            throw new RuntimeException("illegal server port!");
        }
    }

    /**
     * 初始化超时时间
     */
    private void initTimeout() {
        String timeout = NetworkDataOperations.getInstance().getNetworkParamSettings().getCommunicationTimeout();
        if (!TextUtils.isEmpty(timeout) && Utils.isNumeric(timeout)) {
            connectTimeout = Integer.parseInt(timeout) * 1000;
            if (connectTimeout > DEFAULT_TIMEOUT) {
                connectTimeout = DEFAULT_TIMEOUT;
            }
            socketTimeout = connectTimeout;
        }
    }

    void Transaction(byte[] sendBuff, int sendLen, byte[] recBuff, int[] recLen) throws Exception {
        LogUtil.e(Constant.TAG, "Connect to " + serverIP + " : " + serverPort);
        try {
            if (sendLen <= 0 || sendLen > 1024 * 3) {
                return;
            }
            socket = new Socket();
            socket.setSoTimeout(socketTimeout);
            socket.setSoLinger(true, 0);
            socket.connect(new InetSocketAddress(serverIP, serverPort), connectTimeout);
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
            outputStream.write(sendBuff, 0, sendLen);
            outputStream.flush();

            // 等待server数据就绪,小米扫码支付会偶现inputStream.available=2的情况，
            // 现改为如果收到的字节数过短则继续等待
            while (inputStream.available() <= receiveDataLen) {
                Thread.sleep(50);
            }

            int len = -1;
            int index = 0;
            while ((len = inputStream.available()) > 0) {
                index += inputStream.read(recBuff, index, len);
                Thread.sleep(10);
            }

            recLen[0] = index; // 接收的总字节数
        } catch (SocketTimeoutException e) {
            e.printStackTrace();
            // 接口请求超时切换到IP
            switchIP();
            throw new Exception("68");
        } catch (Exception e) {
            e.printStackTrace();
            // 接口请求异常切换IP
            switchIP();
            throw new Exception("E4");
        } finally {
            closePOSP();
        }
    }

    /**
     * 切换IP
     */
    private void switchIP() {
        // 接口请求异常切换到IP
        Configs configs = Configs.getInstance();
        if (configs.USE_BACKUP_IP()) {
            configs.setUSE_BACKUP_IP(false);
        } else {
            configs.setUSE_BACKUP_IP(true);
        }
        LogUtil.e(Constant.TAG, "是否使用备用IP:  " + configs.USE_BACKUP_IP());
    }

    /**
     * 断开连接
     */
    public void interrupt() {
        closePOSP();
    }

    /**
     * 断开连接，释放资源
     */
    private void closePOSP() {
        close(inputStream);
        close(outputStream);
        close(socket);

        inputStream = null;
        outputStream = null;
        socket = null;
    }

    private void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 校验MAC
    private boolean VerifyMAC(byte[] receiveBuff) {
        if ((receiveBuff[23] & 0x01) == 0x00) {
            return true;
        }

        byte[] pMac = new byte[8];
        byte[] nMac = new byte[8];
        System.arraycopy(receiveBuff, receiveBuff.length - 8, pMac, 0, 8);
        TerminalSecure.GenerateMAC(receiveBuff);
        System.arraycopy(receiveBuff, receiveBuff.length - 8, nMac, 0, 8);
        return Arrays.equals(pMac, nMac);
    }

    private boolean validIP(String ip) {
        if (ip == null || ip.isEmpty())
            return false;
        String newIp = ip.trim();
        if (newIp.length() < 6 & newIp.length() > 15)
            return false;
        try {
            String rule = "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.)" +
                    "{3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
            Pattern pattern = Pattern.compile(rule);
            Matcher matcher = pattern.matcher(ip);
            return matcher.matches();
        } catch (PatternSyntaxException ex) {
            return false;
        }
    }


}
